package com.cat.orm.util;

import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class SimpleJsonUtil {
    
    private final static Logger logger = LoggerFactory.getLogger(SimpleJsonUtil.class);
    
    private final static ObjectMapper objectMapper = initObjectMapper();

    private static ObjectMapper initObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 是否可以解析带有/* //格式的注释的json
        objectMapper.configure(Feature.ALLOW_COMMENTS, true);
        // 是否可以解析带有/* //格式的注释的json
        objectMapper.configure(Feature.ALLOW_YAML_COMMENTS, true);
        // 是否可以解析带有单引号的字符串
        objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
        // // 是否可以解析结束语控制字符
        // objectMapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        // // 是否可以解析以"0"为开头的数字(如: 000001),解析时则忽略0
        // objectMapper.configure(Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
        // 若json的属性比对应的java类多 是否抛出异常
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 不使用get set方法 直接使用变量名进行序列化/反序列化
        objectMapper.setVisibility(PropertyAccessor.SETTER, Visibility.NONE);
        objectMapper.setVisibility(PropertyAccessor.GETTER, Visibility.NONE);
        objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
        // 注册各种常用的类的解析器
        SimpleModule module = new SimpleModule();
        // 扫描自定义解析类
        objectMapper.registerModule(module);
        return objectMapper;
    }

    /**
     * 对象转为json
     *
     * @param obj
     * @return
     */
    public static String toJson(Object obj) {
        try {
            String jsonStr = objectMapper.writeValueAsString(obj);
            return jsonStr;
        } catch (JsonProcessingException e) {
            logger.error("objToJsonString error.", e);
        }
        return ReflectionToStringBuilder.toString(obj, ToStringStyle.JSON_STYLE);
    }

    /**
     * 对象转为json格式的字节流
     *
     * @param obj
     * @return
     */
    public static byte[] toJsonBytes(Object obj) {
        try {
            return objectMapper.writeValueAsBytes(obj);
        } catch (JsonProcessingException e) {
            logger.error("objToJsonBytes error.", e);
        }
        return ReflectionToStringBuilder.toString(obj, ToStringStyle.JSON_STYLE).getBytes(StandardCharsets.UTF_8);
    }

    /**
     * json转为对象
     * @param jsonBytes bytes
     * @param clazz 要转的类
     * @return
     */
    public static <T> T toObject(byte[] jsonBytes, Class<T> clazz) throws IOException {
        if (jsonBytes == null || jsonBytes.length <= 0) {
            return null;
        }
        try {
            String json = new String(jsonBytes, StandardCharsets.UTF_8);
            T obj = objectMapper.readValue(json, clazz);
            return obj;
        } catch (JsonProcessingException e) {
            logger.error("jsonBytesToObject error", e);
            throw e;
        }
    }

    /**
     * json转为对象
     *
     * @param <T>
     * @param jsonStr
     * @param clazz
     * @return
     * @throws JsonProcessingException
     */
    public static <T> T toObject(String jsonStr, Class<T> clazz) throws JsonProcessingException {
        if (StringUtils.isEmpty(jsonStr)) {
            return null;
        }
        try {
            T obj = objectMapper.readValue(jsonStr, clazz);
            return obj;
        } catch (JsonProcessingException e) {
            logger.error("jsonToObject error", e);
            throw e;
        }
    }
}
